grammar decTest::Grammar is PCT::Grammar;

rule TOP {
    <statement>*
    [ $ || <panic: 'Syntax error'> ]
    {*}
}

token ws {
    <!ww>
    [ '--' \N* \n? | \s+ | ['version:' \s+ \d+ '.' \d+] ]*
}

rule statement {
    | <test>	{*} #= test
    | <context>	{*} #= context
}

rule test {
    <testname> <operation> <decnumber> [ <decnumber> ]* '->' <decnumber> [ <status> ]*
    {*}
}

token testname {
    \w+
}

token operation {
    [ 'fma' | 'multiply' | 'subtract' | 'divideint' | 'divide' 
      | 'remainder' | 'minus' | 'apply' | 'exp' | 'add' | 'ln'
      | 'log10' | 'power' | 'abs' | 'squareroot' ]
}

token decnumber {
    ['\'' | '"']? <number> ['\'' | '"']?
    {*}
}

token number { :i
    ['+'|'-']? [ 
        [ [\d+ '.'? \d*] | ['.'? \d+] ] ['e' ['+'|'-']? \d+ ]? 
        | [ 'inf' 'inity'? ]
        | [ 's'? 'nan' \d* ]
        | '#'
    ]
    {*}
}

token status {
    | 'Inexact' 
    | 'Rounded' 
    | 'Invalid_operation' 
    | 'Overflow'
    | 'Underflow' 
    | 'Subnormal' 
    | 'Clamped' 
    | 'Invalid_context'
    | 'Division_undefined' 
    | 'Division_by_zero' 
    | 'Division_impossible'
}

rule context {
    | <context_field> <rounding_mode>	{*} #= rounding_mode
    | <context_field> <integer> 	{*} #= integer
}

token context_field { 
    | 'clamp:'	    	{*} #= set_clamp
    | 'maxexponent:'	{*} #= set_emax
    | 'maxExponent:'	{*} #= set_emax
    | 'minexponent:'	{*} #= set_emin
    | 'minExponent:'	{*} #= set_emin
    | 'precision:'	    {*} #= set_digits
    | 'Precision:'	    {*} #= set_digits
    | 'rounding:'	    {*} #= set_rounding_mode
    | 'extended:'	    {*} #= set_extended
}

token integer {
    ['+'|'-']?\d+
    {*}
}

token rounding_mode {
    | 'half_up'		{*} #= .DEC_ROUND_HALF_UP
    | 'half_down'	{*} #= .DEC_ROUND_HALF_DOWN
    | 'half_even'	{*} #= .DEC_ROUND_HALF_EVEN
    | 'down'		{*} #= .DEC_ROUND_DOWN
    | 'up'		{*} #= .DEC_ROUND_UP
    | 'floor' 		{*} #= .DEC_ROUND_FLOOR
    | 'ceiling'		{*} #= .DEC_ROUND_CEILING
}

# vim: expandtab shiftwidth=4 ft=perl6:
